
#pragma once

#include "utils.hpp"

// 进行用户管理
// 用户表的对应操作有:新增用户 , 登录验证 , 查找(根据ID或名称) , 获胜, 输

class User_table
{

    void Get_user_message(MYSQL_RES *res, Json::Value &user)
    {
        MYSQL_ROW row = mysql_fetch_row(res);

        user["uid"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = row[1];
        user["score"] = (Json::UInt64)std::stol(row[2]);
        user["total_count"] = std::stoi(row[3]);
        user["win_count"] = std::stoi(row[4]);
    }

public:
    User_table(const std::string &host, const std::string &user, const std::string &passwd,
               const std::string &database, const uint16_t port)
    {
        _mysql = Mysql_util::init(host, user, passwd, database, port);
    }

    bool insert(const Json::Value &user)
    {
#define INSERT "insert into user values(null , '%s' , sha2('%s' , 256) , 1000 , 0 ,0)"

        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), INSERT, user["username"].asCString(), user["password"].asCString());
        int ret = Mysql_util::exec(_mysql, sql);
        return ret;
    }

    bool login(Json::Value &user)
    {
#define LOGIN "select uid , username , score , total_count , win_count from user where username='%s' and password=sha2('%s' , 256)"

        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), LOGIN, user["username"].asCString(), user["password"].asCString());

        MYSQL_RES *res;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            bool ret = Mysql_util::exec(_mysql, sql);
            if(!ret)
            {
                return false;
            }
            res = mysql_store_result(_mysql);
        }
        if (mysql_num_rows(res) == 0)
        {
            return false;
        }
        Get_user_message(res, user);
        return true;
    }

    bool select_by_id(uint64_t uid, Json::Value &user)
    {
#define SELECT_BY_ID "select uid , username ,  score , total_count , win_count from user where uid=%ld"
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), SELECT_BY_ID, uid);

        MYSQL_RES *res;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            Mysql_util::exec(_mysql, sql);
            res = mysql_store_result(_mysql);
        }
        if (mysql_num_rows(res) == 0)
        {
            return false;
        }
        Get_user_message(res, user);
        return true;
    }

    bool select_by_username(const std::string &username, Json::Value &user)
    {
#define SELECT_BY_USERNAME "select  uid , username , score , total_count , win_count from user where username='%s'"
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), SELECT_BY_USERNAME, username.c_str());

        MYSQL_RES *res;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            Mysql_util::exec(_mysql, sql);
            res = mysql_store_result(_mysql);
        }
        if (mysql_num_rows(res) == 0)
        {
            return false;
        }

        Get_user_message(res, user);

        return true;
    }

    void win(uint64_t uid)
    {
#define USER_WIN "update user set score=score+30, total_count=total_count+1 ,win_count=win_count+1 where uid=%ld"
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), USER_WIN, uid);
        Mysql_util::exec(_mysql, sql);
    }

    void lose(uint64_t uid)
    {
#define USER_LOSE "update user set score=score-30, total_count=total_count+1 where uid=%ld"
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), USER_LOSE, uid);
        Mysql_util::exec(_mysql, sql);
    }

private:
    MYSQL *_mysql;
    std::mutex _mtx;
};